﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Configuration;

namespace DreamIn.Structures.Ftp
{
    /// <summary>
    /// FTP client specialized for any files and folders
    /// </summary>
    class FTPTransfer
    {
        /// <summary>
        /// FTP server host address
        /// </summary>
        private String remoteHost;

        /// <summary>
        /// FTP server username
        /// </summary>
        private String remoteUser;

        /// <summary>
        /// FTP server password
        /// </summary>
        private String remotePass;

        /// <summary>
        /// Constructor of class FTPTransfer
        /// Uses connection strings from 'app.config' to initialize atributes
        /// </summary>
        public FTPTransfer()
        {
            //remoteHost = ConfigurationManager.ConnectionStrings["RemoteHost"].ToString();
            //remoteUser = ConfigurationManager.ConnectionStrings["RemoteUser"].ToString();
            //remotePass = ConfigurationManager.ConnectionStrings["RemotePass"].ToString();
            remoteHost = "127.0.0.1";
            remotePass = "dreamin";
            remoteUser = "dreamin";
        }

        /// <summary>
        /// Uploads the file from local 'filepath' to ftp 'serverPath'
        /// </summary>
        /// <param name="serverPath"> .../serverFilename.extension </param>
        /// <param name="filePath"> .../localFilename.extension </param>
        /// <returns> TRUE if the file is successfully stored on ftp server </returns>
        public bool UploadFile(String serverPath, String filePath)
        {
            Uri uri = CreateFTPUri(serverPath);
            Stream requestStream = null;
            FileStream fileStream = null;
            FtpWebResponse response = null;
            try
            {
                FtpWebRequest request = WebRequest.Create(uri.ToString()) as FtpWebRequest;
                request.Credentials = new NetworkCredential(remoteUser, remotePass);
                request.Method = WebRequestMethods.Ftp.UploadFile;

                requestStream = request.GetRequestStream();
                fileStream = File.Open(filePath, FileMode.Open);
                byte[] buffer = new byte[1024];
                int i;
                while ((i = fileStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    requestStream.Write(buffer, 0, i);
                }
                fileStream.Close();
                requestStream.Close();
                response = request.GetResponse() as FtpWebResponse;
                FtpStatusCode statusCode = response.StatusCode;
                if (statusCode != FtpStatusCode.ClosingData)
                {
                    return false;
                }
                response.Close();
            }
            catch (Exception e)
            {
                return false;
            }
            finally
            {
                if (fileStream != null) fileStream.Close();
                if (requestStream != null) requestStream.Close();
                if (response != null) response.Close();
            }
            return true;

        }

        /// <summary>
        /// Downloads the file from ftp 'serverPath' to local 'destinationPath'
        /// </summary>
        /// <param name="serverPath"> .../serverFilename.extension </param>
        /// <param name="destinationPath"> ../localFilename.extension </param>
        /// <returns> TRUE if the file is successfully stored on local path </returns>
        public bool DownloadFile(String serverPath, String destinationPath)
        {
            Uri uri = CreateFTPUri(serverPath);
            Stream requestStream = null;
            FileStream fileStream = null;
            FtpWebResponse response = null;
            try
            {
                FtpWebRequest request = WebRequest.Create(uri.ToString()) as FtpWebRequest;
                request.Credentials = new NetworkCredential(remoteUser, remotePass);
                request.Method = WebRequestMethods.Ftp.DownloadFile;

                response = (FtpWebResponse)request.GetResponse();
                requestStream = response.GetResponseStream();
                fileStream = new FileStream(destinationPath, FileMode.Create);
                byte[] buffer = new byte[2047];
                int i = 0;
                do
                {
                    i = requestStream.Read(buffer, 0, buffer.Length);
                    fileStream.Write(buffer, 0, i);
                }
                while (i != 0);
                fileStream.Flush();
                fileStream.Close();
                requestStream.Close();
                response.Close();
            }
            catch (Exception e)
            {
                return false;
            }
            finally
            {
                if (fileStream != null) fileStream.Close();
                if (requestStream != null) requestStream.Close();
                if (response != null) response.Close();
            }
            return true;
        }

        /// <summary>
        /// Creates correct ftp Uri format
        /// </summary>
        /// <param name="path"></param>
        /// <returns> ftp://remoteHost:21/path </returns>
        private Uri CreateFTPUri(String path)
        {
            UriBuilder uriB = new UriBuilder("ftp", remoteHost, 21, path);
            if (uriB.Uri.Scheme == Uri.UriSchemeFtp)
                return uriB.Uri;
            return null;
        }

        /// <summary>
        /// Creates a directory on ftp server 
        /// </summary>
        /// <param name="serverPath"> The path of the parent directory </param>
        /// <param name="directoryName"> The name of the new directory </param>
        /// <returns> TRUE if the directory is successfully created on server </returns>
        public bool CreateDirectory(String serverPath, String directoryName)
        {
            FtpWebResponse response = null;
            try
            {
                Uri uri = CreateFTPUri(serverPath + "/" + directoryName);
                FtpWebRequest request = WebRequest.Create(uri.ToString()) as FtpWebRequest;
                request.Credentials = new NetworkCredential(remoteUser, remotePass);
                request.Method = WebRequestMethods.Ftp.MakeDirectory;
                response = request.GetResponse() as FtpWebResponse;
                FtpStatusCode statusCode = response.StatusCode;
                if (statusCode != FtpStatusCode.PathnameCreated)
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
            finally
            {
                if (response != null) response.Close();
            }
            return true;
        }

        /// <summary>
        /// Checks if the directory already exists on ftp server
        /// </summary>
        /// <param name="path"> The path of the parent directory </param>
        /// <param name="directoryName"> The directory name to look for </param>
        /// <returns> TRUE if directory exists on server </returns>
        public bool DirectoryExists(String path, String directoryName)
        {
            Stream responseStream = null;
            FtpWebResponse response = null;
            try
            {
                Uri uri = CreateFTPUri(path);
                FtpWebRequest request = WebRequest.Create(uri.ToString()) as FtpWebRequest;
                request.Credentials = new NetworkCredential(remoteUser, remotePass);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                response = request.GetResponse() as FtpWebResponse;
                responseStream = response.GetResponseStream();
                String directoryStringList;
                using (StreamReader reader = new StreamReader(responseStream))
                {
                    directoryStringList = reader.ReadToEnd();
                }
                response.Close();
                String s = directoryName + Environment.NewLine;
                s = s.Substring(0, s.Length - 1);
                if (directoryStringList.Contains(s))
                    return true;
            }
            catch (Exception e)
            {
                return false;
            }
            finally
            {
                if (responseStream != null) responseStream.Close();
                if (response != null) response.Close();
            }
            return false;
        }

        /// <summary>
        /// Gets a list with the name of files from 'serverDirectoryPath'
        /// </summary>
        /// <param name="serverDirectoryPath"> The path of the server directory </param>
        /// <returns> List of strings </returns>
        public List<String> GetFileNames(String serverDirectoryPath)
        {
            List<String> fileNames = new List<String>();
            Stream responseStream = null;
            FtpWebResponse response = null;
            try
            {
                Uri uri = CreateFTPUri(serverDirectoryPath);
                FtpWebRequest request = WebRequest.Create(uri.ToString()) as FtpWebRequest;
                request.Credentials = new NetworkCredential(remoteUser, remotePass);
                request.Method = WebRequestMethods.Ftp.ListDirectory;
                response = request.GetResponse() as FtpWebResponse;
                responseStream = response.GetResponseStream();
                using (StreamReader reader = new StreamReader(responseStream))
                {
                    String fileName = reader.ReadLine();
                    while (fileName != null)
                    {
                        fileNames.Add(fileName.Substring(fileName.LastIndexOf(@"/") + 1));
                        fileName = reader.ReadLine();
                    }
                }
                response.Close();
            }
            catch (Exception e)
            {
                return fileNames;
            }
            finally
            {
                if (responseStream != null) responseStream.Close();
                if (response != null) response.Close();
            }
            return fileNames;
        }
    }
}
